package controller

import (
	"github.com/gin-gonic/gin"
	"my_go_open/utils"
	"net/http"
	"strings"
)

type JsonResp struct {
	Code    uint        `json:"code"`
	Msg     string      `json:"msg"`
	Payload interface{} `json:"payload"`
}

type FuncCheckRequest func(c *gin.Context, row *utils.MysqlRow) (uint, error)

func WriteJsonError(c *gin.Context, code uint, msg string) {
	c.JSON(http.StatusOK, &JsonResp{
		Code: code,
		Msg:  msg,
	})
}

func WriteJsonSuccess(c *gin.Context, data interface{}) {
	c.JSON(http.StatusOK, &JsonResp{
		Code:    200,
		Payload: data,
	})
}

// TableGetOne 按主键查询数据（GET方法）
func TableGetOne(
	mt *utils.MysqlTable,
	funcCheck FuncCheckRequest,
	funcFixRet func(c *gin.Context, row *utils.MysqlRow, err error),
) func(c *gin.Context) {
	return func(c *gin.Context) {
		row := &utils.MysqlRow{}
		pk := mt.PK
		(*row)[pk] = c.Query(pk)
		if funcCheck != nil {
			if code, err := funcCheck(c, row); err != nil {
				WriteJsonError(c, code, err.Error())
				return
			}
		}
		row, err := mt.GetOne(row.ToStr(pk))
		if funcFixRet != nil {
			funcFixRet(c, row, err)
			return
		}
		if err != nil {
			WriteJsonError(c, http.StatusInternalServerError, err.Error())
			return
		}
		if row == nil {
			WriteJsonError(c, http.StatusNotFound, "data not found")
			return
		}
		WriteJsonSuccess(c, row)
	}
}

// TableInsert 新增数据（POST方法）
func TableInsert(
	mt *utils.MysqlTable,
	mode uint8,
	funcCheck FuncCheckRequest,
	funcFixRet func(c *gin.Context, row *utils.MysqlRow, newId int64, insertErr error),
) func(c *gin.Context) {
	return func(c *gin.Context) {
		row := &utils.MysqlRow{}
		_ = c.PostForm(mt.PK)
		for key, values := range c.Request.PostForm {
			(*row)[key] = utils.StripXSS(values[0], true)
		}
		if funcCheck != nil {
			if code, err := funcCheck(c, row); err != nil {
				WriteJsonError(c, code, err.Error())
				return
			}
		}
		var newId int64
		var insertErr error
		switch mode {
		case 0:
			newId, insertErr = mt.Insert(row)
		case 1:
			newId, insertErr = mt.InsertIgnore(row)
		case 2:
			newId, insertErr = mt.InsertReplace(row)
		case 3:
			newId, insertErr = mt.InsertDuplicate(row)
		}
		if funcFixRet != nil {
			funcFixRet(c, row, newId, insertErr)
			return
		}
		if insertErr != nil {
			WriteJsonError(c, http.StatusInternalServerError, insertErr.Error())
			return
		}
		WriteJsonSuccess(c, map[string]int64{
			"new_id": newId,
		})
	}
}

// TableUpdate 按主键更新数据（POST方法）
func TableUpdate(
	mt *utils.MysqlTable,
	funcCheck FuncCheckRequest,
	funcFixRet func(c *gin.Context, row *utils.MysqlRow, num int64, err error),
) func(c *gin.Context) {
	return func(c *gin.Context) {
		row := &utils.MysqlRow{}
		pk := mt.PK
		_ = c.PostForm(mt.PK)
		for key, values := range c.Request.PostForm {
			(*row)[key] = utils.StripXSS(values[0], true)
		}
		(*row)[pk] = c.Query(pk)
		if funcCheck != nil {
			if code, err := funcCheck(c, row); err != nil {
				WriteJsonError(c, code, err.Error())
				return
			}
		}
		num, err := mt.UpdateById(row, row.ToStr(pk))
		if funcFixRet != nil {
			funcFixRet(c, row, num, err)
			return
		}
		if err != nil {
			WriteJsonError(c, http.StatusInternalServerError, err.Error())
			return
		}
		WriteJsonSuccess(c, map[string]int64{
			"updated": num,
		})
	}
}

// TableList 分页查询数据（GET方法）
func TableList(
	mt *utils.MysqlTable,
	funcCheck FuncCheckRequest,
	funcFixRet func(row *utils.MysqlRow) error,
) func(c *gin.Context) {
	return func(c *gin.Context) {
		row := &utils.MysqlRow{}
		(*row)["page"] = c.DefaultQuery("page", "1")
		(*row)["numPerPage"] = c.DefaultQuery("num_per_page", "10")
		(*row)["queryOrder"] = c.DefaultQuery("order", "`"+mt.PK+"` DESC")
		if funcCheck != nil {
			if code, err := funcCheck(c, row); err != nil {
				WriteJsonError(c, code, err.Error())
				return
			}
		}
		params := make([]interface{}, 0)
		if (*row)["params"] != nil {
			params = (*row)["params"].([]interface{})
		}
		rows := make([]*utils.MysqlRow, 0)
		totalItem, totalPage, curPage, err := mt.SelPage(func(row *utils.MysqlRow) error {
			if funcFixRet != nil {
				if err := funcFixRet(row); err != nil {
					return err
				}
			}
			rows = append(rows, row)
			return nil
		}, row.ToInt64("page"), row.ToInt64("numPerPage"), row.ToStr("queryWhere"), row.ToStr("queryOrder"), row.ToStr("selCols"), params...)
		if err != nil {
			WriteJsonError(c, http.StatusInternalServerError, err.Error())
			return
		}
		WriteJsonSuccess(c, &utils.MysqlRow{
			"total_items": totalItem,
			"total_pages": totalPage,
			"cur_page":    curPage,
			"list":        rows,
		})
	}
}

// TableDelete 按主键删除一条或多条记录（POST方法）
func TableDelete(
	mt *utils.MysqlTable,
	funcCheck FuncCheckRequest,
	funcFixRet func(c *gin.Context, row *utils.MysqlRow, num int64, err error),
) func(c *gin.Context) {
	return func(c *gin.Context) {
		row := &utils.MysqlRow{}
		pk := mt.PK
		(*row)[pk] = c.PostForm(pk)
		if funcCheck != nil {
			if code, err := funcCheck(c, row); err != nil {
				WriteJsonError(c, code, err.Error())
				return
			}
		}
		ids := make([]interface{}, 0)
		for _, id := range strings.Split(row.ToStr(pk), ",") {
			ids = append(ids, id)
		}
		num, err := mt.DelByIds(ids...)
		if funcFixRet != nil {
			funcFixRet(c, row, num, err)
			return
		}
		if err != nil {
			WriteJsonError(c, http.StatusInternalServerError, err.Error())
			return
		}
		WriteJsonSuccess(c, map[string]int64{
			"deleted": num,
		})
	}
}

// TableRoutes 批量添加路由
func TableRoutes(rg *gin.RouterGroup, mt *utils.MysqlTable) {
	api := rg.Group(mt.Name)
	{
		api.GET("add_one", TableInsert(mt, 0, nil, nil))
		api.POST("get_one", TableGetOne(mt, nil, nil))
		api.POST("update_one", TableUpdate(mt, nil, nil))
		api.GET("list", TableList(mt, nil, nil))
		api.POST("delete", TableDelete(mt, nil, nil))
	}
}
